package com.ls.fw.data.search.impl.dao.base.impl;

import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.DoubleField;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.document.FloatField;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.LongField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.highlight.Formatter;
import org.apache.lucene.search.highlight.Fragmenter;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.search.highlight.SimpleSpanFragmenter;

import com.ls.fw.common.beanparser.bean.PageBean;
import com.ls.fw.common.beanparser.enums.OrderType;
import com.ls.fw.common.beanparser.handler.BeanHandler;
import com.ls.fw.common.beanparser.schema.Column;
import com.ls.fw.common.beanparser.schema.Expression;
import com.ls.fw.common.beanparser.schema.Order;
import com.ls.fw.common.beanparser.statement.Select;
import com.ls.fw.common.utils.ObjectUtil;
import com.ls.fw.data.search.impl.dao.base.BaseIndexDao;
import com.ls.fw.data.search.impl.lucene.bean.ValueType;
import com.ls.fw.data.search.impl.lucene.exception.IndexException;
import com.ls.fw.data.search.impl.lucene.parser.WhereParser;
import com.ls.fw.data.search.impl.lucene.util.BeanParameterUtil;
import com.ls.fw.data.search.impl.lucene.util.IndexUtil;

/**
 * @author 李昇
 * 2014年4月13日 下午2:54:13
 */
public abstract class BaseIndexDaoImpl<T,PK>  extends LuceneDaoImpl implements BaseIndexDao<T,PK>{

	protected Class<?> entityClass = null;
	protected BeanHandler beanHandler  = new BeanHandler();
	
	
	public BaseIndexDaoImpl(String indexFilePath) throws IndexException {
		super(indexFilePath);
		init();
	}
	
	@SuppressWarnings("unchecked")
	private void init(){
		Class<?> c = getClass();
		Type t = c.getGenericSuperclass();
		if (t instanceof ParameterizedType) {
			Type[] p = ((ParameterizedType) t).getActualTypeArguments();
			this.entityClass = (Class<T>) p[0];
		}
	}
	
	public BaseIndexDaoImpl(String indexFilePath,Analyzer analyzer) throws IndexException {
		super(indexFilePath,analyzer);
		init();
	}
	
	public Formatter getHighlighterFormatter(){
		return new SimpleHTMLFormatter("<font color=\"red\">","</font>");
	}
	
	@Override
	public Highlighter getHighlighter(Query query){
		 /**自定义标注高亮文本标签*/  
		 Formatter formatter = this.getHighlighterFormatter();  
	     /**创建QueryScorer*/  
	     QueryScorer scorer=new QueryScorer(query);  
	     /**创建Fragmenter*/  
	     Fragmenter fragmenter = new SimpleSpanFragmenter(scorer);  
	     Highlighter highlight=new Highlighter(formatter,scorer);  
	     highlight.setTextFragmenter(fragmenter);
	     return highlight;
	}
	
	public Object doc2Obj(final Document doc,final Query query,final boolean high){
		return this.doc2Obj(doc, entityClass, query, high);
	}
	
	@Override
	public Object doc2Obj(final Document doc,final Class<?> requiredType, final Query query
			, final boolean high){
		Object model = null;
		try {
			model = requiredType.newInstance();
		} catch (InstantiationException e1) {
			throw new IndexException(e1.getMessage(),e1);
		} catch (IllegalAccessException e1) {
			throw new IndexException(e1.getMessage(),e1);
		}
		java.lang.reflect.Field[] fields = model.getClass().getDeclaredFields();
		Highlighter highlight = this.getHighlighter(query);
		Analyzer analyzer =  this.getAnalyzer();
		for (int i = 0; i < fields.length; i++) {
			java.lang.reflect.Field f = fields[i];
	        f.setAccessible(true);   
	        try {
	             this.setValue(f, model, doc, highlight, analyzer, high);
			} catch (Exception e) {
				e.printStackTrace();
			}  
		}
		return model;
	}
	
	private void setValue(final java.lang.reflect.Field f, final Object target
			, final Document doc, final Highlighter highlight
			, final Analyzer analyzer,final boolean high){
		
		 Class<?> classObj = target.getClass();  
		if (!this.isCollection(f)) {
			if (this.isJavaClass(f.getType())) { // 该表的字段
				 // 获取属性名为name的属性  
				java.lang.reflect.Field nameField = null;
				try {
					nameField = classObj.getDeclaredField(f.getName());
					// 设置通过反射访问该Field时取消访问权限检查  
			        nameField.setAccessible(true);  
			        Object value = this.getValue(f,f.getName(),doc,highlight,analyzer,high);
			        //System.out.println(nameField.getName()+":"+value);
			        // 设置新的值  
			        if(value!=null){
			        	nameField.set(target, value);
			        }
				} catch (Exception e) {
					e.printStackTrace();
				} 
			}else {// 该表的外键
				 // 获取属性名为name的属性  
				Class<?> fkclass = f.getType();
				try {
					 
					Object fkobj = fkclass.newInstance();
					java.lang.reflect.Field eField = null;
			        eField = classObj.getDeclaredField(f.getName());
						// 设置通过反射访问该Field时取消访问权限检查  
			        eField.setAccessible(true); 
			        java.lang.reflect.Field nameField = null;
					nameField = fkclass.getDeclaredField(DEFAULT_PK);
					// 设置通过反射访问该Field时取消访问权限检查  
			        nameField.setAccessible(true); 
			        Object value = this.getValue(nameField,f.getName(),doc,highlight,analyzer,high);
			        //System.out.println(nameField.getName()+":"+value);
			        if(value!=null){
				        nameField.set(fkobj, value);
				        eField.set(target, fkobj);
			        }
				} catch (Exception e) {
					e.printStackTrace();
				} 
			}
		} 
	}
	
	/**
	 * 是否为集合类型
	 * @author Defender
	 * 2014年2月15日 下午1:41:51
	 * @param field
	 * @return
	 */
    private boolean isCollection(java.lang.reflect.Field field){
    	boolean flag = false;
    	String typeStr = field.getGenericType().toString();
    	if (("interface java.util.Collection".equals(typeStr))
				|| ("interface java.util.HashMap".equals(typeStr))
				|| ("interface java.util.List".equals(typeStr))
				|| ("interface java.util.Map".equals(typeStr))
				|| ("interface java.util.Set".equals(typeStr))
				|| ("class java.util.Collection".equals(typeStr))
				|| ("class java.util.HashMap".equals(typeStr))
				|| ("class java.util.List".equals(typeStr))
				|| ("class java.util.Map".equals(typeStr)) 
				|| ("class java.util.Set".equals(typeStr))) {
    		flag = true;
    	}
    	return flag;
    }
	
	/**
	 * 判断是否为java本身的类型
	 * 
	 * @param clz
	 * @return
	 */
	private boolean isJavaClass(Class<?> clz) {
		return clz != null && clz.getClassLoader() == null;
	}

	private String setValueHighlighter(final String fieldName
			, final String value, final Highlighter highlight
			, final Analyzer analyzer,final boolean high){
		String val = value;
		try {
    		if(!(value==null || "".equals(value)) && this.isHigherShow(fieldName)){
				//System.out.println(f.getName()+":"+val);
				TokenStream tokenStream = analyzer.tokenStream(fieldName, new StringReader(String.valueOf(val)));    
				String valStr = highlight.getBestFragment(tokenStream, String.valueOf(val));
				//System.out.println(valStr);
				val = (valStr==null?val:valStr);
    		}
		}catch (Exception e) {
			e.printStackTrace();
		}
		return val;
	}
	
	public boolean isHigherShow(String name){
		return true;
	}
	
	
	@Override
	public Object getValue(final java.lang.reflect.Field f,final String indexName, final Document doc
			, final Highlighter highlight, final Analyzer analyzer
			, final boolean high){
		
		String val = doc.get(indexName);
		Object value = null;
		if(f.getType().equals(java.sql.Date.class)){
			
			if(!StringUtils.isBlank(val) && !"0".equals(val) && !"null".equals(val)){
				value = new java.sql.Date(new Date(Long.valueOf(val)).getTime());
			}
		}else if(f.getType().equals(java.util.Date.class)){
			
			if(!StringUtils.isBlank(val) && !"0".equals(val) && !"null".equals(val)){
				value = new Date(Long.valueOf(val));
			}
		}else if(f.getType().equals(Timestamp.class)){
			
			if(!StringUtils.isBlank(val) && !"0".equals(val) && !"null".equals(val)){
				value = new Timestamp(new Date(Long.valueOf(val)).getTime());
			}
		}else if(f.getType().equals(Time.class)){
			
			if(!StringUtils.isBlank(val) && !"0".equals(val) && !"null".equals(val)){
				value = new Time(new Date(Long.valueOf(val)).getTime());
			}
		}else if(f.getType().equals(Integer.class)
				||f.getType().equals(int.class)){
			
			if(!StringUtils.isBlank(val) && !"null".equals(val)){
				value = Integer.valueOf(val);
			}
		}else if(f.getType().equals(Short.class)
				||f.getType().equals(short.class)){
			
			if(!StringUtils.isBlank(val) && !"null".equals(val)){
				value = Short.valueOf(val);
			}
		}else if(f.getType().equals(Byte.class)
				||f.getType().equals(byte.class)){
			
			if(!StringUtils.isBlank(val) && !"null".equals(val)){
				value = Byte.valueOf(val);
			}
		}else if(f.getType().equals(Long.class)
				||f.getType().equals(long.class)){
			
			if(!StringUtils.isBlank(val) && !"null".equals(val)){
				value = Long.valueOf(val);
			}
		}else if(f.getType().equals(Float.class)
				||f.getType().equals(float.class)){
			
			if(!StringUtils.isBlank(val) && !"null".equals(val)){
				value = Float.valueOf(val);
			}
		}else if(f.getType().equals(Double.class)
				||f.getType().equals(double.class)){
			
			if(!StringUtils.isBlank(val) && !"null".equals(val)){
				value = Double.valueOf(val);
			}
		}else if(f.getType().equals(Boolean.class)
				||f.getType().equals(boolean.class)){
			
			if(!StringUtils.isBlank(val) && !"null".equals(val)){
				value = Boolean.valueOf(val);
			}
		}else{
			value = val;
		}
        if(value!=null){
        	if(high){
				if(f.getType().equals(String.class)){
					value = this.setValueHighlighter(f.getName(), val, highlight, analyzer, high);
				}
        	}					
        }
        return value;
	}
	
	
	@Override
	public Document getDocument(final T model){
		Document doc = new Document();
		try {
			List<Column>  list = beanHandler.toColumns(model);
			if(list!=null){
				for (Column column : list) {
					Field field = this.getField(column);
					if(field!=null){
						doc.add(field);
					}
				}
				Field field = new LongField("creattime",new Date().getTime(),Field.Store.YES);
		 		doc.add(field);
			}
		} catch (SecurityException e1) {
			e1.printStackTrace();
		} catch (NoSuchMethodException e1) {
			e1.printStackTrace();
		} catch (Exception e1) {
			e1.printStackTrace();
		}
//		Field field = null;
//		Class<?> classObj = model.getClass();
//		Map<String, Object> map = BeanParameterUtil.getClassInfoForIndex(model);
//		Set<String> set = map.keySet();
//		boolean isColl = false;
//		java.lang.reflect.Field f = null;
//		for (String fieldName : set) {
// 			Object value = map.get(fieldName);
// 			try {
// 				f = classObj.getDeclaredField(fieldName);
// 				isColl = isCollection(f);
//			} catch (Exception e) {
//				e.printStackTrace();
//			} 
// 			if(!isColl){
// 				if (this.isJavaClass(f.getType()) || this.isDate(f)) { // 该表的字段
// 					field = this.handlField(f,value);
// 				}else {// 该表的外键
// 					field = this.handlFKField(f, value);
// 				}
// 			}
//			if(field!=null){
//				doc.add(field);
//			}
// 		}
// 		field = new LongField("creattime",new Date().getTime(),Field.Store.YES);
// 		doc.add(field);
		return doc;
	}
	
	private Field getField(Column column){
		Field field = null;
		Object value = column.getValue();
		String fieldName = column.getIndexName();
//		if(ObjectUtil.isEmpty(fieldName)){
//			fieldName = column.getName();
//		}
		fieldName = column.getName();
		Store store = column.isStore()?Field.Store.YES:Field.Store.NO;
		FieldType type = new FieldType();
		type.setIndexed(column.isIndex());
		type.setStored(column.isStore());
		type.setTokenized(column.isToken());
		switch(column.getIndexFieldType()){
			case booleanx:
				field = new StringField(fieldName, String.valueOf(value), store);
				break;
			case date:
				type.setNumericType(FieldType.NumericType.LONG);
				if(value instanceof java.sql.Date){
					if(ObjectUtil.isEmpty(value)){
						field = new LongField(fieldName,0L,type);
					}else{
						field = new LongField(fieldName,((java.sql.Date)value).getTime(),type);
					}
				}else if(value instanceof java.util.Date){
					if(ObjectUtil.isEmpty(value)){
						field = new LongField(fieldName,0L,type);
					}else{
						field = new LongField(fieldName,((Date)value).getTime(),type);
					}
				}else{
					if(ObjectUtil.isEmpty(value)){
						field = new LongField(fieldName,0L,type);
					}else{
						field = new LongField(fieldName,Long.parseLong(value.toString()),type);
					}
				}
				break;
			case doublex:
				type.setNumericType(FieldType.NumericType.DOUBLE);
				if(ObjectUtil.isEmpty(value)){
					field = new DoubleField(fieldName,0D,type);
				}else{
					field = new DoubleField(fieldName,Double.parseDouble(String.valueOf(value)),type);
				}
				break;
			case file:
				field = new StringField(fieldName, String.valueOf(value), store);
				break;
			case floatx:
				type.setNumericType(FieldType.NumericType.FLOAT);
				if(ObjectUtil.isEmpty(value)){
					field = new FloatField(fieldName,0F,type);
				}else{
					field = new FloatField(fieldName,Float.parseFloat(String.valueOf(value)),type);
				}
				break;
			case intx:
				type.setNumericType(FieldType.NumericType.INT);
				if(ObjectUtil.isEmpty(value)){
					field = new IntField(fieldName,0,type);
				}else{
					field = new IntField(fieldName,Integer.parseInt(String.valueOf(value)),type);
				}
				break;
			case longx:
				type.setNumericType(FieldType.NumericType.LONG);
				if(ObjectUtil.isEmpty(value)){
					field = new LongField(fieldName,0L,type);
				}else{
					field = new LongField(fieldName,Long.parseLong(String.valueOf(value)),type);
				}
				break;
			case number:
				type.setNumericType(FieldType.NumericType.DOUBLE);
				if(ObjectUtil.isEmpty(value)){
					field = new DoubleField(fieldName,0D,type);
				}else{
					field = new DoubleField(fieldName,Double.parseDouble(String.valueOf(value)),type);
				}
				break;
			case string:
				field = new StringField(fieldName, String.valueOf(value), store);
				break;
			case text:
				field = new TextField(fieldName, String.valueOf(value), store);
				break;
			case time:
				type.setNumericType(FieldType.NumericType.LONG);
				if(ObjectUtil.isEmpty(value)){
					field = new LongField(fieldName,0L,type);
				}else{
					field = new LongField(fieldName,((Time)value).getTime(),type);
				}
				break;
			case timestamp:
				type.setNumericType(FieldType.NumericType.LONG);
				if(ObjectUtil.isEmpty(value)){
					field = new LongField(fieldName,0L,type);
				}else{
					field = new LongField(fieldName,((Timestamp)value).getTime(),type);
				}
				break;
			default:
				field = new StringField(fieldName, String.valueOf(value), store);
				break;
		}
		return field;
	}
	
	@Override
	public Field handlFKField(final java.lang.reflect.Field fkField, final Object value){
		Field field = null;
		if(value!=null){
			try {
		       Object value1 = BeanParameterUtil.getFieldValue(value, DEFAULT_PK);
		       field = this.handlField(fkField,value1);
			} catch (Exception e) {
				e.printStackTrace();
			} 
		}
		return field;
	}
		
	
	@Override
	public Field handlField(final java.lang.reflect.Field f, final Object value){
		String fieldName = f.getName();
		Field field = null;
		if(value instanceof java.sql.Date){
			if(value==null || "".equals(value)){
				field = new LongField(fieldName,0L,Field.Store.YES);
			}else{
				field = new LongField(fieldName,((java.sql.Date)value).getTime(),Field.Store.YES);
			}
		}else if(value instanceof java.util.Date){
			if(value==null || "".equals(value)){
				field = new LongField(fieldName,0L,Field.Store.YES);
			}else{
				field = new LongField(fieldName,((Date)value).getTime(),Field.Store.YES);
			}
		}else if(value instanceof Timestamp){
			if(value==null || "".equals(value)){
				field = new LongField(fieldName,0L,Field.Store.YES);
			}else{
				field = new LongField(fieldName,((Timestamp)value).getTime(),Field.Store.YES);
			}
		}else if(value instanceof Time){
			if(value==null || "".equals(value)){
				field = new LongField(fieldName,0L,Field.Store.YES);
			}else{
				field = new LongField(fieldName,((Time)value).getTime(),Field.Store.YES);
			}
		}else if(value instanceof Byte||f.getType().equals(byte.class)){
			if(value==null || "".equals(value)){
				field = new IntField(fieldName,0,Field.Store.YES);
			}else{
				field = new IntField(fieldName,Integer.parseInt(String.valueOf(value)),Field.Store.YES);
			}
		}else if(value instanceof Integer||f.getType().equals(int.class)){
			if(value==null || "".equals(value)){
				field = new IntField(fieldName,0,Field.Store.YES);
			}else{
				field = new IntField(fieldName,Integer.parseInt(String.valueOf(value)),Field.Store.YES);
			}
		}else if(value instanceof Short||f.getType().equals(short.class)){
			if(value==null || "".equals(value)){
				field = new IntField(fieldName,0,Field.Store.YES);
			}else{
				field = new IntField(fieldName,Integer.parseInt(String.valueOf(value)),Field.Store.YES);
			}
		}else if(value instanceof Long||f.getType().equals(long.class)){
			if(value==null || "".equals(value)){
				field = new LongField(fieldName,0L,Field.Store.YES);
			}else{
				field = new LongField(fieldName,Long.parseLong(String.valueOf(value)),Field.Store.YES);
			}
		}else if(value instanceof Float||f.getType().equals(float.class)){
			if(value==null || "".equals(value)){
				field = new FloatField(fieldName,0F,Field.Store.YES);
			}else{
				field = new FloatField(fieldName,Float.parseFloat(String.valueOf(value)),Field.Store.YES);
			}
		}else if(value instanceof Double||f.getType().equals(double.class)){
			if(value==null || "".equals(value)){
				field = new DoubleField(fieldName,0D,Field.Store.YES);
			}else{
				field = new DoubleField(fieldName,Double.parseDouble(String.valueOf(value)),Field.Store.YES);
			}
		}else{
			field = new StringField(fieldName, String.valueOf(value), Field.Store.YES);
		}
		return field;
	}
	
	@Override
	public void add(final T model) throws IndexException{
		IndexWriter writer = this.getIndexWriter();
		try {
			Document doc = this.getDocument(model);
			writer.addDocument(doc);
			if(this.isAutoCommit()){
				writer.commit();
			}
		} catch (Exception e) {
			if(this.isAutoCommit()){
				try {
					writer.rollback();
				} catch (IOException e1) {
					throw new IndexException(e1.getMessage(),e1.getCause());
				}
			}
			throw new IndexException(e.getMessage(),e.getCause());
		} finally {
		}
	}
	
	
	@Override
	public void add(final List<T> list) throws IndexException{
		
		IndexWriter writer = this.getIndexWriter();
		try {
			List<Document> modellist = new ArrayList<Document>(list.size());
			for (T model : list) {
				Document doc = getDocument(model);
				modellist.add(doc);
			}
			writer.addDocuments(modellist);
			if(this.isAutoCommit()){
				writer.commit();
			}
		} catch (Exception e) {
			if(this.isAutoCommit()){
				try {
					writer.rollback();
				} catch (IOException e1) {
					throw new IndexException(e1.getMessage(),e1.getCause());
				}
			}
			throw new IndexException(e.getMessage(),e.getCause());
		} finally {
		}
	}
	
	
	@Override
	public void update(final T model,final PK id) throws IndexException{
		IndexWriter writer = this.getIndexWriter();
		try {
			Term term = new Term(DEFAULT_PK, String.valueOf(id));
			Document doc = this.getDocument(model);
			writer.updateDocument(term, doc);
			if(this.isAutoCommit()){
				writer.commit();
			}
		} catch (Exception e) {
			if(this.isAutoCommit()){
				try {
					writer.rollback();
				} catch (IOException e1) {
					throw new IndexException(e1.getMessage(),e1.getCause());
				}
			}
			throw new IndexException(e.getMessage(),e.getCause());
		} finally {
		}
	}
	
	
	@Override
	public void delete(final PK id) throws IndexException{
		this.delete(DEFAULT_PK, id);
	}
	
	
	@Override
	public void deleteAll() throws IndexException{
		IndexWriter writer = this.getIndexWriter();
		try {
			// 删除时多条记录删除
			writer.deleteAll();
			if(this.isAutoCommit()){
				writer.commit();
			}
		} catch (Exception e) {
			if(this.isAutoCommit()){
				try {
					writer.rollback();
				} catch (IOException e1) {
					throw new IndexException(e1.getMessage(),e1.getCause());
				}
			}
			throw new IndexException(e.getMessage(),e.getCause());
		} finally {
		}
	}
	
	
	@Override
	public void delete(final String pkname,final PK id) throws IndexException{
		IndexWriter writer = this.getIndexWriter();
		try {
			//NumericRangeQuery
			ValueType t = IndexUtil.getValueType(id);
			Query query = null;
			switch(t){
				case NONE:
					throw new IndexException("id不能为空！");
				case DOUBLE:
					query = NumericRangeQuery.newDoubleRange(pkname, Double.valueOf(String.valueOf(id)), Double.valueOf(String.valueOf(id)), true, true);
					writer.deleteDocuments(query);
					break;
				case FLOAT:
					query = NumericRangeQuery.newFloatRange(pkname, Float.valueOf(String.valueOf(id)), Float.valueOf(String.valueOf(id)), true, true);
					writer.deleteDocuments(query);
					break;
				case LONG:
					query = NumericRangeQuery.newLongRange(pkname, Long.valueOf(String.valueOf(id)), Long.valueOf(String.valueOf(id)), true, true);
					writer.deleteDocuments(query);
					break;
				case INT:
					query = NumericRangeQuery.newIntRange(pkname, Integer.valueOf(String.valueOf(id)), Integer.valueOf(String.valueOf(id)), true, true);
					writer.deleteDocuments(query);
					break;
				case STRING:
					Term term = null;
				    term = new Term(pkname, String.valueOf(id));
				    writer.deleteDocuments(term);
					break;
			}
			if(this.isAutoCommit()){
				writer.commit();
			}
		} catch (Exception e) {
			if(this.isAutoCommit()){
				try {
					writer.rollback();
				} catch (IOException e1) {
					throw new IndexException(e1.getMessage(),e1.getCause());
				}
			}
			throw new IndexException(e.getMessage(),e.getCause());
		} finally {
		}
	}
	
	@Override
	public Query getQuery(final Select select) throws IndexException{
//		BooleanQueryBuilder and = BooleanQueryBuilder.builder();
		Query query = null;
//		QueryBuilder builder = new QueryBuilder(this.getAnalyzer());
//		Analyzer analyzer =  this.getAnalyzer();
		List<Expression> list = select.getWhereInfo().getList();
		if(list!=null && list.size()>0){
			WhereParser w = new WhereParser(select.getWhereInfo());
			query = (BooleanQuery) w.getQuery();
		}else{
 			 query = new MatchAllDocsQuery();
		}
		return query;
	}
	
	@Override
	public Sort getSort(final Select select) throws IndexException{
		/**
		 * 
	    // 评分降序，评分一样时后索引的排前面   
	    new SortField[] { SortField.FIELD_SCORE, new SortField(null, SortField.DOC, true) }   
	    // 评分升序，评分一样时后索引的排前面，呵呵，此为最不相关的排前面，挺有趣的   
	    new SortField[] { new SortField(null, SortField.SCORE, true), new SortField(null, SortField.DOC, true) }  
		 * */
		// 组件排序条件语句
		List<SortField> sortList = new ArrayList<SortField>();
		List<Order> orders = select.getOrderInfo().getList();
		if (select.hasOrder()) {
			for (Order indexOrder : orders) {
					SortField.Type type = SortField.Type.STRING;
					if(indexOrder.getName().equals("creattime")){
						type = SortField.Type.LONG;
					}else if(indexOrder.getName().equals(DEFAULT_PK)){
						type = SortField.Type.LONG;
					} 
					if(indexOrder.getValueType()!=null){
						ValueType t = IndexUtil.getValueType(indexOrder.getValueType());
						switch(t){
						case DOUBLE:
							type = SortField.Type.DOUBLE;
							break;
						case FLOAT:
							type = SortField.Type.FLOAT;
							break;
						case LONG:
							type = SortField.Type.LONG;
							break;
						case INT:
							type = SortField.Type.INT;
							break;
						case STRING:
							type = SortField.Type.STRING;
							break;
						default:
							type = SortField.Type.STRING;
							break;
						}
					}
					if (indexOrder.getOrderType()==OrderType.DESC) {
						sortList.add(new SortField(indexOrder.getName(), type, true));
					} else {
						sortList.add(new SortField(indexOrder.getName(), type, false));
					}
			}
		} else {
			//sortList.add(new SortField("id", SortField.INT, true));
		}
		Sort sort = null;
		if(sortList!=null && sortList.size()>0){
			sort = new Sort(sortList.toArray(new SortField[sortList.size()]));
		}else{
			if(select.isFullTextQuery()){
				sortList.add(SortField.FIELD_SCORE);
				//sortList.add(new SortField(DEFAULT_PK, SortField.Type.LONG, true));
			}
			if(sortList!=null && sortList.size()>0){
				sort = new Sort(sortList.toArray(new SortField[sortList.size()]));
			}
		}
		return sort;
	}
	
	@Override
	public PageBean query(final Select select) throws IndexException{
		return this.query(select, this.entityClass);
	}
	
	@Override
	public PageBean query(final Select select,Class<?> requiredType) throws IndexException{
		IndexSearcher searcher = new IndexSearcher(this.getIndexReader());
		 
		Query query = this.getQuery(select);
		Sort sort = this.getSort(select); 
		int firstResult = (int) ((select.getPage() - 1) *select.getPageSize());
		if(firstResult<0){
			firstResult = 0;
		}
		PageBean pageBean = null;
		List<T> list = null;
		try{
			int maxResult = searcher.getIndexReader().maxDoc();
			int n = maxResult;
			if(select.getPageSize()>0){
				n = firstResult + select.getPageSize();
			    n = (int) Math.min(n,maxResult);
			    if(n<=0){
			    	n = 1;
			    }
			}
		    System.out.println("全文搜索条件："+query.toString());
		    System.out.println("order条件："+sort);
		    TopDocs topDocs = null;
		    if(sort==null){
		    	topDocs = searcher.search(query, null, n);
			}else{
				topDocs = searcher.search(query, null, n , sort);
			}
		    int totalCount = topDocs.totalHits;// 总记录数
			ScoreDoc[] hits = topDocs.scoreDocs;
			int length = (int) Math.min(firstResult + maxResult, hits.length);
			System.out.println("n:"+n);
			System.out.println("numDocs:"+searcher.getIndexReader().numDocs());
		    System.out.println("maxDocs:"+searcher.getIndexReader().maxDoc());
		    System.out.println("deleteDocs:"+searcher.getIndexReader().numDeletedDocs());
			System.out.println("hits:"+hits.length);
			System.out.println("firstResult:"+firstResult);
			System.out.println("length:"+length);
			int size = length-firstResult;
			if(size>0){
				list = new ArrayList<T>(size);
			}else{
				list = new ArrayList<T>(1);
			}
			for (int i = firstResult; i < length; i++) {
				int DocId = hits[i].doc;
				Document doc1 = searcher.doc(DocId);
				//System.out.println(doc1);
				@SuppressWarnings("unchecked")
				T obj = (T) this.doc2Obj(doc1, requiredType, query, select.isHigh());;
				if(obj!=null){
					list.add(obj);
				}
			}
			pageBean = PageBean.getInstance(select.getPage(), select.getPageSize(), totalCount, list);
		}catch (Exception e) {
			throw new IndexException(e.getMessage(),e);
		}finally{
		}
		return pageBean;
	}
	 
	
	@Override
	public long getSize(final Select select) throws IndexException{
		long size = 0L;
		IndexReader reader = this.getIndexReader();
		IndexSearcher searcher = new IndexSearcher(reader);
		if(!select.hasCondition()){
			size = reader.maxDoc();
			return size;
		}else{
			Query query = this.getQuery(select);
			try{
				int n = 1;
			    TopDocs topDocs = null;
			    topDocs = searcher.search(query, null, n);
//			    TopScoreDocCollector topCollector = TopScoreDocCollector.create(reader.maxDoc(), false);
//			     searcher.search(query,topCollector);
//			     ScoreDoc[] docs = topCollector.topDocs(3).scoreDocs;
//			     System.out.println(docs.length);
			    //MaxDoc()是所有文档数，包括删除和未删除的文档。
			    //NumDocs()则是所有未被删除的文档总数
			    size = topDocs.totalHits;// 总记录数
			}catch (Exception e) {
				throw new IndexException(e.getMessage(),e.getCause());
			}finally{
			}
		}
		return size;
	}
}
